package com.rp.common.config.shiro;

/**
 * 类说明:
 *
 * @author ****
 * @date 2020-11-25 11:25  新建
 */

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.rp.system.user.entity.SysPermission;
import com.rp.system.user.entity.SysRole;
import com.rp.system.user.entity.SysUser;
import com.rp.system.user.service.*;
import com.rp.common.utils.NullIs;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.LinkedHashSet;
import java.util.Set;

/**
 * @author: wangsaichao
 * @date: 2018/5/10
 * @description: 在Shiro中，最终是通过Realm来获取应用程序中的用户、角色及权限信息的
 * 在Realm中会直接从我们的数据源中获取Shiro需要的验证信息。可以说，Realm是专用于安全框架的DAO.
 */
public class ShiroRealm extends AuthorizingRealm {

    @Autowired
    private SysUserService sysUserService;

    @Autowired
    private SysRoleService sysRoleService;

    @Autowired
    private SysPermissionService sysPermissionService;

    /**
     * 验证用户身份
     *
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //获取用户名密码 第一种方式
        //String username = (String) authenticationToken.getPrincipal();
        //String password = new String((char[]) authenticationToken.getCredentials());
        //获取用户名 密码 第二种方式
        UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) authenticationToken;
        String username = usernamePasswordToken.getUsername();
        String password = new String(usernamePasswordToken.getPassword());
        System.out.println(username);
        System.out.println(password);
        //从数据库查询用户信息
        SysUser user = sysUserService.findSysUserByUsername(username);
        //可以在这里直接对用户名校验,或者调用 CredentialsMatcher 校验
        if (user == null) {
            //秘钥登录
            user = sysUserService.getOne(new QueryWrapper<SysUser>().eq("client_id", username));
            if (user == null) {
                throw new UnknownAccountException("用户不存在！");
            }else{
                usernamePasswordToken.setUsername(user.getUsername());
                //调用 CredentialsMatcher 校验 还需要创建一个类 继承CredentialsMatcher  如果在上面校验了,这个就不需要了
                //配置自定义权限登录器 参考博客：
                SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user.getUsername(),sysUserService.selectClientSecret(user.getClientId()),new MyByteSource(user.getUsername() + user.getSalt()),getName());
                return info;
            }
        }else{
            //密码登录
            System.out.println(user);
            if(user.getStatus() == 2){
                //冻结
                throw new LockedAccountException();
            }
            //调用 CredentialsMatcher 校验 还需要创建一个类 继承CredentialsMatcher  如果在上面校验了,这个就不需要了
            //配置自定义权限登录器 参考博客：
            SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user.getUsername(), user.getPassword(), new MyByteSource(user.getUsername() + user.getSalt()), getName());
            return info;
        }

    }

    /**
     * 授权用户权限
     *
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        //获取用户
        String username = (String) SecurityUtils.getSubject().getPrincipal();
        if(NullIs.isEmpty(username)){
            return authorizationInfo;
        }
        SysUser user = sysUserService.findSysUserByUsername(username);
        if(NullIs.isEmpty(user)){
            return authorizationInfo;
        }
        //获取用户角色
        Set<SysRole> roles = sysRoleService.findRolesByUserId(user.getId());

        if(!roles.isEmpty()){
            //添加角色
            for (SysRole role : roles) {
                authorizationInfo.addRole(role.getRoleName());
            }
            //获取用户权限
            LinkedHashSet<SysPermission> permissions = sysPermissionService.findPermissionsByRoleId(roles);
            if(!permissions.isEmpty()){
                //添加权限
                for (SysPermission permission : permissions) {
                    if(StringUtils.isNotBlank(permission.getPerms())){
                        authorizationInfo.addStringPermission(permission.getPerms());
                    }
                }
            }

        }
        return authorizationInfo;
    }

    /**
     * 重写方法,清除当前用户的的 授权缓存
     *
     * @param principals
     */
    @Override
    public void clearCachedAuthorizationInfo(PrincipalCollection principals) {
        super.clearCachedAuthorizationInfo(principals);
    }

    /**
     * 重写方法，清除当前用户的 认证缓存
     *
     * @param principals
     */
    @Override
    public void clearCachedAuthenticationInfo(PrincipalCollection principals) {
        super.clearCachedAuthenticationInfo(principals);
    }

    @Override
    public void clearCache(PrincipalCollection principals) {
        super.clearCache(principals);
    }

    /**
     * 自定义方法：清除所有 授权缓存
     */
    public void clearAllCachedAuthorizationInfo() {
        getAuthorizationCache().clear();
    }

    /**
     * 自定义方法：清除所有 认证缓存
     */
    public void clearAllCachedAuthenticationInfo() {
        getAuthenticationCache().clear();
    }

    /**
     * 自定义方法：清除所有的  认证缓存  和 授权缓存
     */
    public void clearAllCache() {
        clearAllCachedAuthenticationInfo();
        clearAllCachedAuthorizationInfo();
    }

}